using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using ICSharpCode.TextEditor.Actions;
using ICSharpCode.TextEditor.Document;
using ICSharpCode.TextEditor.Util;

namespace ICSharpCode.TextEditor
{
    public class TextAreaClipboardHandler
    {
        public delegate bool ClipboardContainsTextDelegate();

        private TextArea textArea;

        public static ClipboardContainsTextDelegate GetClipboardContainsText;

        private const string LineSelectedType = "MSDEVLineSelect";

        private const string MuiltSelectedType = "MSDEVLinesSelect";

        [ThreadStatic]
        private static int SafeSetClipboardDataVersion;

        public bool EnableCut => textArea.EnableCutOrPaste;

        public bool EnableCopy => true;

        public bool EnablePaste
        {
            get
            {
                if (!textArea.EnableCutOrPaste)
                {
                    return false;
                }
                ClipboardContainsTextDelegate getClipboardContainsText = GetClipboardContainsText;
                if (getClipboardContainsText != null)
                {
                    return getClipboardContainsText();
                }
                try
                {
                    return Clipboard.ContainsText();
                }
                catch (ExternalException)
                {
                    return false;
                }
            }
        }

        public bool EnableDelete => textArea.SelectionManager.HasSomethingSelected && !textArea.SelectionManager.SelectionIsReadonly;

        public bool EnableSelectAll => true;

        public event CopyTextEventHandler CopyText;

        public TextAreaClipboardHandler(TextArea textArea)
        {
            this.textArea = textArea;
            textArea.SelectionManager.SelectionChanged += DocumentSelectionChanged;
        }

        private void DocumentSelectionChanged(object sender, EventArgs e)
        {
        }

        private bool CopyTextToClipboard(string stringToCopy, bool asLine)
        {
            if (stringToCopy.Length > 0)
            {
                DataObject dataObject = new DataObject();
                dataObject.SetData(DataFormats.UnicodeText, autoConvert: true, stringToCopy);
                if (asLine)
                {
                    MemoryStream memoryStream = new MemoryStream(1);
                    memoryStream.WriteByte(1);
                    dataObject.SetData("MSDEVLineSelect", autoConvert: false, memoryStream);
                }
                if (textArea.Document.HighlightingStrategy.Name != "Default")
                {
                    dataObject.SetData(DataFormats.Rtf, RtfWriter.GenerateRtf(textArea));
                    dataObject.SetData(DataFormats.Html, HtmlWriter.GenerateHtml(textArea));
                }
                if (textArea.SelectionManager.IsMutilSelect)
                {
                    int num = 0;
                    string text = "";
                    foreach (ISelection item in textArea.SelectionManager.selectionCollection)
                    {
                        string selectedText = item.SelectedText;
                        int num2 = checked(item.EndPosition.Column - item.StartPosition.Column);
                        if (num <= num2)
                        {
                            num = num2;
                        }
                        text += selectedText;
                    }
                    text = text + "__maxLength__=" + num;
                    dataObject.SetData("MSDEVLinesSelect", text);
                }
                OnCopyText(new CopyTextEventArgs(stringToCopy));
                SafeSetClipboard(dataObject);
                return true;
            }
            return false;
        }

        private static void SafeSetClipboard(object dataObject)
        {
            int version = ++SafeSetClipboardDataVersion;
            try
            {
                Clipboard.SetDataObject(dataObject, copy: true);
            }
            catch (ExternalException)
            {
                Timer timer = new Timer();
                timer.Interval = 100;
                timer.Tick += delegate
                {
                    timer.Stop();
                    timer.Dispose();
                    if (SafeSetClipboardDataVersion == version)
                    {
                        try
                        {
                            Clipboard.SetDataObject(dataObject, copy: true, 10, 50);
                        }
                        catch (ExternalException)
                        {
                        }
                    }
                };
                timer.Start();
            }
        }

        private bool CopyTextToClipboard(string stringToCopy)
        {
            return CopyTextToClipboard(stringToCopy, asLine: false);
        }

        public void Cut(object sender, EventArgs e)
        {
            if (textArea.SelectionManager.HasSomethingSelected)
            {
                if (CopyTextToClipboard(textArea.SelectionManager.SelectedText) && !textArea.SelectionManager.SelectionIsReadonly)
                {
                    textArea.BeginUpdate();
                    textArea.Caret.Position = textArea.SelectionManager.SelectionCollection[0].StartPosition;
                    textArea.SelectionManager.RemoveSelectedText();
                    textArea.EndUpdate();
                }
            }
            else if (textArea.Document.TextEditorProperties.CutCopyWholeLine)
            {
                int lineNumberForOffset = textArea.Document.GetLineNumberForOffset(textArea.Caret.Offset);
                LineSegment lineSegment = textArea.Document.GetLineSegment(lineNumberForOffset);
                string text = textArea.Document.GetText(lineSegment.Offset, lineSegment.TotalLength);
                textArea.SelectionManager.SetSelection(textArea.Document.OffsetToPosition(lineSegment.Offset), textArea.Document.OffsetToPosition(checked(lineSegment.Offset + lineSegment.TotalLength)));
                if (CopyTextToClipboard(text, asLine: true) && !textArea.SelectionManager.SelectionIsReadonly)
                {
                    textArea.BeginUpdate();
                    textArea.Caret.Position = textArea.Document.OffsetToPosition(lineSegment.Offset);
                    textArea.SelectionManager.RemoveSelectedText();
                    textArea.Document.RequestUpdate(new TextAreaUpdate(TextAreaUpdateType.PositionToEnd, new TextLocation(0, lineNumberForOffset)));
                    textArea.EndUpdate();
                }
            }
        }

        public void Copy(object sender, EventArgs e)
        {
            if (!CopyTextToClipboard(textArea.SelectionManager.SelectedText) && textArea.Document.TextEditorProperties.CutCopyWholeLine)
            {
                int lineNumberForOffset = textArea.Document.GetLineNumberForOffset(textArea.Caret.Offset);
                LineSegment lineSegment = textArea.Document.GetLineSegment(lineNumberForOffset);
                string text = textArea.Document.GetText(lineSegment.Offset, lineSegment.TotalLength);
                CopyTextToClipboard(text, asLine: true);
            }
        }

        public void Paste(object sender, EventArgs e)
        {
            if (!textArea.EnableCutOrPaste)
            {
                return;
            }
            int num = 0;
            checked
            {
                while (true)
                {
                    try
                    {
                        IDataObject dataObject = Clipboard.GetDataObject();
                        if (dataObject == null)
                        {
                            break;
                        }
                        bool dataPresent = dataObject.GetDataPresent("MSDEVLineSelect");
                        if (!dataObject.GetDataPresent(DataFormats.UnicodeText))
                        {
                            break;
                        }
                        string text = (string)dataObject.GetData(DataFormats.UnicodeText);
                        if (string.IsNullOrEmpty(text))
                        {
                            break;
                        }
                        textArea.Document.UndoStack.StartUndoGroup();
                        try
                        {
                            if (textArea.SelectionManager.IsMutilSelect)
                            {
                                int num2 = 0;
                                int num3 = -1;
                                string text2 = (string)dataObject.GetData("MSDEVLinesSelect");
                                if (string.IsNullOrEmpty(text2))
                                {
                                    text2 = text;
                                }
                                num3 = text2.IndexOf("__maxLength__=");
                                if (num3 != -1)
                                {
                                    num2 = Convert.ToInt32(text2.Substring(num3 + "__maxLength__=".Length));
                                    text2 = text2.Substring(0, num3 - Environment.NewLine.Length);
                                }
                                else
                                {
                                    num2 = text2.Length;
                                }
                                string[] array = Regex.Split(text2, Environment.NewLine);
                                if (textArea.SelectionManager.HasSomethingMutilLinesSeleted)
                                {
                                    ICSharpCode.TextEditor.Actions.Delete.DeleteSelection(textArea);
                                }
                                char[] array2 = new char[num2];
                                for (int i = 0; i < textArea.SelectionManager.selectionCollection.Count; i++)
                                {
                                    if (i < array.Length)
                                    {
                                        ArrayUtility.Clear(array2, ' ');
                                        char[] array3 = array[i].ToCharArray();
                                        Array.Copy(array3, array2, array3.Length);
                                    }
                                    string str = new string(array2);
                                    if (array.Length == 1)
                                    {
                                        str = array[0];
                                    }
                                    ISelection selection = textArea.SelectionManager.selectionCollection[i];
                                    int num4 = textArea.Document.PositionToOffset(selection.StartPosition);
                                    int num5 = textArea.Document.PositionToOffset(selection.EndPosition);
                                    int num6 = textArea.Document.PositionToOffset(selection.StartPosition);
                                    textArea.Caret.Position = selection.StartPosition;
                                    textArea.InsertString(str, paste: true);
                                    int num7 = textArea.Document.PositionToOffset(textArea.Caret.Position) - num6;
                                    num4 += num7;
                                    num5 += num7;
                                    selection.StartPosition = textArea.Document.OffsetToPosition(num4);
                                    selection.EndPosition = textArea.Document.OffsetToPosition(num5);
                                }
                                break;
                            }
                            if (textArea.SelectionManager.HasSomethingSelected)
                            {
                                textArea.Caret.Position = textArea.SelectionManager.SelectionCollection[0].StartPosition;
                                textArea.SelectionManager.RemoveSelectedText();
                            }
                            if (dataPresent)
                            {
                                int column = textArea.Caret.Column;
                                textArea.Caret.Column = 0;
                                if (!textArea.IsReadOnly(textArea.Caret.Offset))
                                {
                                    textArea.InsertString(text);
                                }
                                textArea.Caret.Column = column;
                            }
                            else
                            {
                                textArea.InsertString(text);
                            }
                            break;
                        }
                        finally
                        {
                            textArea.Document.UndoStack.EndUndoGroup();
                        }
                    }
                    catch (ExternalException)
                    {
                        if (num > 5)
                        {
                            throw;
                        }
                    }
                    num++;
                }
            }
        }

        public void Delete(object sender, EventArgs e)
        {
            new Delete().Execute(textArea);
        }

        public void SelectAll(object sender, EventArgs e)
        {
            new SelectWholeDocument().Execute(textArea);
        }

        protected virtual void OnCopyText(CopyTextEventArgs e)
        {
            if (CopyText != null)
            {
                CopyText(this, e);
            }
        }
    }
}
